// ----------------------------------------------------------------------------
// diabindEnumDebugStreamData.h
// DIA Enumerate debug stream data
// ----------------------------------------------------------------------------

#pragma once

// ----------------------------------------------------------------------------

namespace diabind
{
// ----------------------------------------------------------------------------

interface IEnumDebugStreamData
{
    virtual ~IEnumDebugStreamData() {}

    virtual std::wstring get_name() = 0;

    virtual LONG get_Count() = 0;
    virtual std::string Item(DWORD index) = 0;
};
typedef boost::shared_ptr< IEnumDebugStreamData > CEnumDebugStreamDataPtr;

// ----------------------------------------------------------------------------

// ----------------------------------------------------------------------------

template< class DiaEnumDebugStreamDataT >
class CEnumDebugStreamDataImpl : public IEnumDebugStreamData
{
    typedef _com_IIID< DiaEnumDebugStreamDataT, &__uuidof(DiaEnumDebugStreamDataT) > CIiid;
    typedef _com_ptr_t< CIiid > CImplPtr;
public:
    explicit CEnumDebugStreamDataImpl(const CImplPtr &pEnumDebugStreamData)
        : m_pEnumDebugStreamData(pEnumDebugStreamData)
    {
        HRESULT hResult = m_pEnumDebugStreamData->get_Count(&m_nCount);
        if (S_OK != hResult)
            throw CException(hResult, "IDiaEnumDebugStreamData::get_Count");
    }

    virtual std::wstring get_name() override
    {
        _bstr_t bstrValue;
        HRESULT hResult = m_pEnumDebugStreamData->get_name(bstrValue.GetAddress());
        if (S_OK != hResult)
            throw CException(hResult, "IDiaEnumDebugStreamData::get_name");
        return std::wstring(bstrValue);
    }

    virtual LONG get_Count() override
    {
        return m_nCount;
    }

    virtual std::string Item(DWORD index) override
    {
        if (index >= static_cast<DWORD>(m_nCount))
            throw CPyException(PyExc_IndexError, "index out of range");

        DWORD dwDataSize;
        HRESULT hResult = 
            m_pEnumDebugStreamData->Item(
                index,
                0,
                &dwDataSize,
                nullptr);
        if (S_OK != hResult)
            throw CException(hResult, "IDiaEnumDebugStreamData::Item");

        if (!dwDataSize)
            return std::string();

        std::vector<BYTE> DataBuf(dwDataSize);
        hResult = 
            m_pEnumDebugStreamData->Item(
                index,
                dwDataSize,
                &dwDataSize,
                &DataBuf[0]);
        if (S_OK != hResult)
            throw CException(hResult, "IDiaEnumDebugStreamData::Item");

        return std::string(DataBuf.begin(), DataBuf.end());
    }

private:
    CImplPtr m_pEnumDebugStreamData;
    LONG m_nCount;
};

}   // namespace diabind

// ----------------------------------------------------------------------------
